package com.suray.basic.wcs.plc.pojo.oper.single;

import com.suray.basic.wcs.plc.config.resolver.PlcAnnotation;
import com.suray.basic.wcs.plc.core.PlcOffset;
import com.suray.basic.wcs.plc.enums.Location;
import com.suray.basic.wcs.plc.enums.PlcDeviceType;
import com.suray.basic.wcs.plc.pojo.DeviceBase;
import com.suray.basic.wcs.utils.Coord;
import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.basic.wcs.utils.WcsFuncUtil;

import java.io.IOException;

/**
 * 移裁机
 */
public class TransPlanter extends DeviceBase implements DeviceInterface {

    final protected static int OPER_OFF = 0;
    final protected static int OPER_ON = 1;
    /**
     * 移栽机任务字
     * AB:
     * A（0-9）：无效；1：升降机升；2：升降机降；3：升降机链条机正转；4：升降机链条机反转；5：升降机链条机停止
     * B(0-2):0:无；1输送线进货；2输送线出货
     */
    //升降机升
    private static final int RISE=10;
    //升降机降
    private static final int DROP=20;
    //升降机链条机正转 进货
    private static final int FORWARD_IN=31;
    //升降机链条机正转 出货
    private static final int FORWARD_OUT=32;
    //升降机链条机反转 进货
    private static final int REVERSE_IN=41;
    //升降机链条机反转 出货
    private static final int REVERSE_OUT=42;
    //升降机链条机 停止
    private static final int REVERSE_STOP=50;

    private static final PlcOffset DEVICE_TYPE = new PlcOffset(0, null);

    private static final PlcOffset IS_OPEN_SHAPE = new PlcOffset(17, 0);
    private static final PlcOffset IS_OPEN_BCR = new PlcOffset(17, 1);
    private static final PlcOffset IS_OPEN_OVERWEIGHT = new PlcOffset(17, 2);

    private static final PlcOffset STOP_STATE = new PlcOffset(18, 8);
    private static final PlcOffset CONTROLLER_MODE_MANUAL = new PlcOffset(18, 1);
    private static final PlcOffset CONTROLLER_MODE_AUTO = new PlcOffset(18, 2);
    private static final PlcOffset MANUAL_UP = new PlcOffset(18, 3);
    private static final PlcOffset MANUAL_DOWN = new PlcOffset(18, 4);
    private static final PlcOffset MANUAL_FORWARD = new PlcOffset(18, 5);
    private static final PlcOffset MANUAL_REVERSE = new PlcOffset(18, 6);
    private static final PlcOffset CLEAR_ERROR_1 = new PlcOffset(18, 7);
    private static final PlcOffset IS_CONTROL = new PlcOffset(18, 8);
    private static final PlcOffset IS_RUNNING = new PlcOffset(18, 9);
    private static final PlcOffset ELEVATOR_STATE = new PlcOffset(18, 10);
    private static final PlcOffset CONVEYOR_STATE = new PlcOffset(18, 11);
    private static final PlcOffset ERROR_STATE = new PlcOffset(18, 12);
    private static final PlcOffset OUT_CARGO_SIGNAL = new PlcOffset(18, 13);
    private static final PlcOffset IN_CARGO_SIGNAL = new PlcOffset(18, 14);
    private static final PlcOffset RISE_IN_PLACE = new PlcOffset(18, 15);
    private static final PlcOffset DROP_IN_PLACE = new PlcOffset(19, 0);

    private static final PlcOffset ERROR_INFO = new PlcOffset(20, null);
    private static final PlcOffset CHECK_NO = new PlcOffset(21, null);
    private static final PlcOffset CURRENT_DEVICE_TYPE = new PlcOffset(22, null);

    //任务号
    private static final PlcOffset TASK_NO = new PlcOffset(25, null);
    //起点设备编号
    private static final PlcOffset TASK_START_LOCATION = new PlcOffset(26, null);
    //终点设备编号
    private static final PlcOffset TASK_END_LOCATION = new PlcOffset(27, null);

    //设备类型  写
    private static final int DEVICETYPE = 0;
    //位移量 写
    private static final int MOVEMENT = 1;
    //升降自动速度 写
    private static final int LIFT_AUTO_SPEED = 2;
    //升降自动加速时间 写
    private static final int LIFT_AUTO_ACC = 3;
    //升降自动减速时间 写
    private static final int LIFT_AUTO_DEC = 4;
    //升降手动速度 写
    private static final int LIFT_MANUAL_SPEED = 5;
    //升降手动加速时间 写
    private static final int LIFT_MANUAL_ACC = 6;
    //升降手动减速时间 写
    private static final int LIFT_MANUAL_DEC = 7;
    //输送线自动速度 写
    private static final int CONVEYOR_AUTO_SPEED = 8;
    //输送线自动加速时间 写
    private static final int CONVEYOR_AUTO_ACC = 9;
    //输送线自动减速时间 写
    private static final int CONVEYOR_AUTO_DEC = 10;
    //输送线手动速度 写
    private static final int CONVEYOR_MANUAL_SPEED = 11;
    //输送线手动加速时间 写
    private static final int CONVEYOR_MANUAL_ACC = 12;
    //输送线手动减速时间 写
    private static final int CONVEYOR_MANUAL_DEC = 13;
    //移裁升降机 写
    private static final int TASK_ACTION = 16;
    //故障清除 写
    private static final int CLEAR_ERROR = 17;
    //下发输送任务
    private static final int SEND_TASK = 28;
    //清除任务信息
    private static final int CLEAR_TASK = 31;


    public TransPlanter(PlcDeviceType plcDeviceType, int startNo, String deviceName, int deviceNo, Coord coord,
                        Location location, Coord lockLocation, long deviceId, Integer gridzMax, Integer gridzRelative,
                        int plcId) {
        super(plcDeviceType, startNo, deviceName, deviceNo, coord, location, lockLocation, deviceId, gridzMax,
                gridzRelative, plcId);
    }

    public Integer getTaskNo() {
        return readPlc(TASK_NO);
    }

    public Integer getTaskStartLocation() {
        return readPlc(TASK_START_LOCATION);
    }

    public Integer getTaskEndLocation() {
        return readPlc(TASK_END_LOCATION);
    }

    @PlcAnnotation("下发输送任务")
    public void sendConveryTask(int taskNo, int startDeviceNo, int endDeviceNo) throws IOException {
        String des = getDeviceStatus();
        while (getTaskNo() != 0) {
            setDeviceStatus("任务号不为0，不能下发任务：" + taskNo);
            WcsFuncUtil.delay(1000);
        }
        setDeviceStatus(des);

        LoggerUtil.info("下发移栽任务，设备：" + getDeviceName() + ", 任务编号：" + taskNo + ", 起点设备：" + startDeviceNo
                + ", 终点设备:" + endDeviceNo, this.getClass());
        int[] data = new int[3];
        data[0] = taskNo;
        data[1] = startDeviceNo;
        data[2] = endDeviceNo;
        oper("发送行驶任务", this.getClass(), SEND_TASK, 10, data);
    }

    @PlcAnnotation("清除任务编号")
    public void clearTaskNo() throws IOException {
        LoggerUtil.info("清除任务编号，设备：" + getDeviceName(), this.getClass());
        oper("清除任务编号", this.getClass(), CLEAR_TASK, 10, 1);
    }

    @PlcAnnotation(value = "设置设备类型")
    public void setDeviceType() throws IOException {
        oper("设置设备类型", this.getClass(), DEVICETYPE, 3, 6);
    }

    public Integer getDeviceType() {
        return readPlc(DEVICE_TYPE);
    }

    public Integer getMovement() {
        return readPlc(new PlcOffset(MOVEMENT, null));
    }

    /**
     * 平台升位移量
     *
     * @return
     */
    @PlcAnnotation(value = "平台升位移量")
    public void setPlatformRiseMovement() throws IOException {
        oper("平台升位移量", this.getClass(), MOVEMENT, 10, 11);
    }

    /**
     * 平台降位移量
     *
     * @return
     */
    @PlcAnnotation(value = "平台降位移量")
    public void setPlatformDropMovement() throws IOException {
        oper("平台降位移量", this.getClass(), MOVEMENT, 10, 12);
    }

    public Integer getLiftAutoSpeed() {
        return readPlc(new PlcOffset(LIFT_AUTO_SPEED, null));
    }

    /**
     * 设置升降自动速度
     *
     * @return
     */
    @PlcAnnotation(value = "设置升降自动速度")
    public void setLiftAutoSpeed(int speed) throws IOException {
        LoggerUtil.info("升降自动速度:" + speed, this.getClass());
        oper("设置升降自动速度", this.getClass(), LIFT_AUTO_SPEED, 10, speed);
    }

    public Integer getLiftAutoAcc() {
        return readPlc(new PlcOffset(LIFT_AUTO_ACC, null));
    }

    /**
     * 设置升降自动加速时间
     *
     * @return
     */
    @PlcAnnotation(value = "设置升降自动加速时间")
    public void setLiftAutoAcc(int time) throws IOException {
        LoggerUtil.info("升降自动加速时间:" + time, this.getClass());
        oper("设置升降自动加速时间", this.getClass(), LIFT_AUTO_ACC, 10, time);
    }

    public Integer getLiftAutoDec() {
        return readPlc(new PlcOffset(LIFT_AUTO_DEC, null));
    }

    /**
     * 设置升降自动减速时间
     *
     * @return
     */
    @PlcAnnotation(value = "设置升降自动减速时间")
    public void setLiftAutoDec(int time) throws IOException {
        LoggerUtil.info("升降自动减速时间:" + time, this.getClass());
        oper("设置升降自动减速时间", this.getClass(), LIFT_AUTO_DEC, 10, time);
    }

    public Integer getLiftManualSpeed() {
        return readPlc(new PlcOffset(LIFT_MANUAL_SPEED, null));
    }

    /**
     * 设置升降手动速度
     *
     * @return
     */
    @PlcAnnotation(value = "设置升降手动速度")
    public void setLiftManualSpeed(int speed) throws IOException {
        LoggerUtil.info("升降手动速度:" + speed, this.getClass());
        oper("设置升降手动速度", this.getClass(), LIFT_MANUAL_SPEED, 10, speed);
    }

    public Integer getLiftManualAcc() {
        return readPlc(new PlcOffset(LIFT_MANUAL_ACC, null));
    }

    /**
     * 设置升降手动加速时间
     *
     * @return
     */
    @PlcAnnotation(value = "设置升降手动加速时间")
    public void setLiftManualAcc(int time) throws IOException {
        LoggerUtil.info("升降手动加速时间:" + time, this.getClass());
        oper("设置升降手动加速时间", this.getClass(), LIFT_MANUAL_ACC, 10, time);
    }

    public Integer getLiftManualDec() {
        return readPlc(new PlcOffset(LIFT_MANUAL_DEC, null));
    }

    /**
     * 设置升降手动减速时间
     *
     * @return
     */
    @PlcAnnotation(value = "设置升降手动减速时间")
    public void setLiftManualDec(int time) throws IOException {
        LoggerUtil.info("升降手动减速时间:" + time, this.getClass());
        oper("设置升降手动减速时间", this.getClass(), LIFT_MANUAL_DEC, 10, time);
    }

    public Integer getConveyorAutoSpeed() {
        return readPlc(new PlcOffset(CONVEYOR_AUTO_SPEED, null));
    }

    /**
     * 设置输送线自动速度
     *
     * @return
     */
    @PlcAnnotation(value = "设置输送线自动速度")
    public void setConveyorAutoSpeed(int speed) throws IOException {
        LoggerUtil.info("输送线自动速度:" + speed, this.getClass());
        oper("设置输送线自动速度", this.getClass(), CONVEYOR_AUTO_SPEED, 10, speed);
    }

    public Integer getConveyorAutoAcc() {
        return readPlc(new PlcOffset(CONVEYOR_AUTO_ACC, null));
    }

    /**
     * 设置输送线自动加速时间
     *
     * @return
     */
    @PlcAnnotation(value = "设置输送线自动加速时间")
    public void setConveyorAutoAcc(int time) throws IOException {
        LoggerUtil.info("输送线自动加速时间:" + time, this.getClass());
        oper("设置输送线自动加速时间", this.getClass(), CONVEYOR_AUTO_ACC, 10, time);
    }

    public Integer getConveyorAutoDec() {
        return readPlc(new PlcOffset(CONVEYOR_AUTO_DEC, null));
    }

    /**
     * 设置输送线自动减速时间
     *
     * @param time
     * @throws IOException
     */
    @PlcAnnotation(value = "设置输送线自动减速时间")
    public void setConveyorAutoDec(int time) throws IOException {
        LoggerUtil.info("输送线自动减速时间:" + time, this.getClass());
        oper("设置输送线自动减速时间", this.getClass(), CONVEYOR_AUTO_DEC, 10, time);
    }

    public Integer getConveyorManualSpeed() {
        return readPlc(new PlcOffset(CONVEYOR_MANUAL_SPEED, null));
    }

    /**
     * 设置输送线手动速度
     *
     * @return
     */
    @PlcAnnotation(value = "设置输送线手动速度")
    public void setConveyorManualSpeed(int speed) throws IOException {
        LoggerUtil.info("输送线手动速度:" + speed, this.getClass());
        oper("设置输送线手动速度", this.getClass(), CONVEYOR_MANUAL_SPEED, 10, speed);
    }

    public Integer getConveyorManualAcc() {
        return readPlc(new PlcOffset(CONVEYOR_MANUAL_ACC, null));
    }

    /**
     * 设置输送线手动加速时间
     *
     * @param time
     * @throws IOException
     */
    @PlcAnnotation(value = "设置输送线手动加速时间")
    public void setConveyorManualAcc(int time) throws IOException {
        LoggerUtil.info("输送线手动加速时间:" + time, this.getClass());
        oper("设置输送线手动加速时间", this.getClass(), CONVEYOR_MANUAL_ACC, 10, time);
    }

    public Integer getConveyorManualDec() {
        return readPlc(new PlcOffset(CONVEYOR_MANUAL_DEC, null));
    }

    /**
     * 设置输送线手动减速时间
     *
     * @param time
     * @throws IOException
     */
    @PlcAnnotation(value = "设置输送线手动减速时间")
    public void setConveyorManualDec(int time) throws IOException {
        LoggerUtil.info("输送线手动减速时间:" + time, this.getClass());
        oper("设置输送线手动减速时间", this.getClass(), CONVEYOR_MANUAL_DEC, 10, time);
    }

    public Integer getTaskAction() {
        return readPlc(new PlcOffset(TASK_ACTION, null));
    }

    /**
     * 平台上升
     *
     * @throws IOException
     */
    @PlcAnnotation(value = "平台上升")
    public void platformRise() throws IOException {
        oper("平台上升", this.getClass(), TASK_ACTION, 10, RISE);
    }
    /**
     * 平台下降
     *
     * @throws IOException
     */
    @PlcAnnotation(value = "平台下降")
    public void platformDrop() throws IOException {
        oper("平台下降", this.getClass(), TASK_ACTION, 10, DROP);
    }
    /**
     * 正转入库
     *
     * @throws IOException
     */
    @PlcAnnotation(value = "正转入库")
    public void platformForwardIn() throws IOException {
        oper("正转入库", this.getClass(), TASK_ACTION, 10, FORWARD_IN);
    }

    /**
     * 正转出库
     *
     * @throws IOException
     */
    @PlcAnnotation(value = "正转出库")
    public void platformForwardOut() throws IOException {
        oper("正转出库", this.getClass(), TASK_ACTION, 10, FORWARD_OUT);
    }

    /**
     * 反转入库
     *
     * @throws IOException
     */
    @PlcAnnotation(value = "反转入库")
    public void platformReverseIn() throws IOException {
        oper("反转入库", this.getClass(), TASK_ACTION, 10, REVERSE_IN);
    }

    /**
     * 反转出库
     *
     * @throws IOException
     */
    @PlcAnnotation(value = "反转出库")
    public void platformReverseOut() throws IOException {
        oper("反转出库", this.getClass(), TASK_ACTION, 10, REVERSE_OUT);
    }

    /**
     * 输送停止
     *
     * @throws IOException
     */
    @PlcAnnotation(value = "输送停止")
    public void platformReverseStop() throws IOException {
        oper("输送停止", this.getClass(), TASK_ACTION, 10, REVERSE_STOP);
    }

    public boolean isClearError() {
        return readPlc(new PlcOffset(CLEAR_ERROR, 8)) == 1;
    }

    /**
     * 故障清除
     *
     * @return
     */
    @PlcAnnotation(value = "故障清除")
    public void setClearError() throws IOException {
        oper("自动升降机故障清除", this.getClass(), CLEAR_ERROR, 10, OPER_ON);
    }

    public boolean isOpenShape() {
        return readPlc(IS_OPEN_SHAPE) == 1;
    }

    public boolean isOpenBcr() {
        return readPlc(IS_OPEN_BCR) == 1;
    }

    public boolean isOpenOverweight() {
        return readPlc(IS_OPEN_OVERWEIGHT) == 1;
    }

    public boolean isStopState() {
        return readPlc(STOP_STATE) == 1;
    }
    public boolean isControllerModeManual() {
        return readPlc(CONTROLLER_MODE_MANUAL) == 1;
    }

    public boolean isControllerModeAuto() {
        return readPlc(CONTROLLER_MODE_AUTO) == 1;
    }

    public boolean isManualUp() {
        return readPlc(MANUAL_UP) == 1;
    }

    public boolean isManualDown() {
        return readPlc(MANUAL_DOWN) == 1;
    }

    public boolean isManualForward() {
        return readPlc(MANUAL_FORWARD) == 1;
    }

    public boolean isManualReverse() {
        return readPlc(MANUAL_REVERSE) == 1;
    }

    public boolean isClearError1() {
        return readPlc(CLEAR_ERROR_1) == 1;
    }

    public boolean isControl() {
        return readPlc(IS_CONTROL) == 1;
    }

    public boolean isRunning() {
        return readPlc(IS_RUNNING) == 1;
    }

    @Override
    public boolean isError() {
        return isErrorState();
    }

    @Override
    public Integer errorCode() {
        return null;
    }

    public boolean isElevatorState() {
        return readPlc(ELEVATOR_STATE) == 1;
    }

    public boolean isConveyorState() {
        return readPlc(CONVEYOR_STATE) == 1;
    }

    public boolean isErrorState() {
        return readPlc(ERROR_STATE) == 1;
    }

    public boolean isInCargoSignalValid() {
        return readPlc(IN_CARGO_SIGNAL) == 1;
    }

    public boolean isOutCargoSignalValid() {
        return readPlc(OUT_CARGO_SIGNAL) == 1;
    }

    public boolean isRiseInPlace() {
        return readPlc(RISE_IN_PLACE) == 1;
    }

    public boolean isDropInPlace() {
        return readPlc(DROP_IN_PLACE) == 1;
    }

    public Integer getErrorInfo() {
        return readPlc(ERROR_INFO);
    }

    public Integer getCheckNo() {
        return readPlc(CHECK_NO);
    }

    public Integer getCurrentDeviceType() {
        return readPlc(CURRENT_DEVICE_TYPE);
    }

    public boolean hasCargo() {
        return isInCargoSignalValid() || isOutCargoSignalValid();
    }

    @Override
    public boolean inCargoSignal() {
        return isInCargoSignalValid();
    }

    @Override
    public boolean outCargoSignal() {
        return isOutCargoSignalValid();
    }

    @Override
    public boolean permitRun() {
        return isControl() && !isRunning();
    }

    @Override
    public boolean canControl() {
        return isControl();
    }

    /**
     * 正转方向为入库光电
     * 反转方向为出库光电
     * @param directionIn
     * @return
     */
    public boolean checkSignalValid(boolean directionIn) {
        if (directionIn) {
            return isInCargoSignalValid();
        } else {
            return isOutCargoSignalValid();
        }
    }
}
